/**
 * 
 */
package com.mobipe.sutto.util;

import static org.jboss.netty.handler.codec.http.HttpHeaders.setContentLength;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;

import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelFutureProgressListener;
import org.jboss.netty.channel.DefaultFileRegion;
import org.jboss.netty.channel.FileRegion;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.stream.ChunkedWriteHandler;
import org.jboss.netty.util.CharsetUtil;


/**
 * @author kohachiro
 * 
 */
public class HttpHandler {

	/**
	 * 
	 */
	public HttpHandler() {
		// TODO Auto-generated constructor stub
	}

	public static void messageReceived(ByteBuffer byteBuffer, Channel channel) {
		final String path = HttpRequest.sanitizeUri(HttpRequest
				.getUri(byteBuffer));

		if (path == null) {
			sendError(channel, FORBIDDEN);
			return;
		}

		File file = new File(path);
		if (file.isHidden() || !file.exists()) {
			sendError(channel, NOT_FOUND);
			return;
		}
		if (!file.isFile()) {
			sendError(channel, FORBIDDEN);
			return;
		}

		RandomAccessFile raf;
		try {
			raf = new RandomAccessFile(file, "r");
			long fileLength = raf.length();

			HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
			setContentLength(response, fileLength);

			// Write the initial line and the header.

			channel.getPipeline().addLast("aggregator",
					new HttpChunkAggregator(65536));
			channel.getPipeline().addLast("encoder", new HttpResponseEncoder());
			channel.getPipeline().addLast("chunkedWriter",
					new ChunkedWriteHandler());
			channel.write(response);

			// Write the content.
			ChannelFuture writeFuture;
			// No encryption - use zero-copy.
			final FileRegion region = new DefaultFileRegion(raf.getChannel(),
					0, fileLength);
			writeFuture = channel.write(region);
			writeFuture.addListener(new ChannelFutureProgressListener() {
				public void operationComplete(ChannelFuture future) {
					region.releaseExternalResources();
				}

				public void operationProgressed(ChannelFuture future,
						long amount, long current, long total) {
					System.out.printf("%s: %d / %d (+%d)%n", path, current,
							total, amount);
				}
			});
			channel.getPipeline().removeLast();
			// Decide whether to close the connection or not.
			// if (!isKeepAlive(request)) {
			// Close the connection when the whole content is written out.
			writeFuture.addListener(ChannelFutureListener.CLOSE);
			// }
		} catch (Exception fnfe) {
			sendError(channel, NOT_FOUND);
			return;
		}

	}

	private static void sendError(Channel channel, HttpResponseStatus status) {
		HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
		response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
		response.setContent(ChannelBuffers.copiedBuffer(
				"Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
		channel.write(response).addListener(ChannelFutureListener.CLOSE);
	}
}
